/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.lge.remoteshot.wifidirect;

import java.util.ArrayList;
import java.util.List;

import android.app.ListFragment;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.ChannelListener;
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.lge.remoteshot.R;
import com.lge.remoteshot.camera.CameraActivity;

/**
 * A ListFragment that displays available peers on discovery and requests the
 * parent activity to handle user interaction events
 */
public class DeviceListFragment extends ListFragment implements PeerListListener, OnClickListener,
		DeviceActionListener, ConnectionInfoListener, ChannelListener {

	private List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
	ProgressDialog progressDialog = null;
	View mContentView = null;
	private WifiP2pDevice serverDevice;

	private boolean isWifiP2PEnabled = false;
	private boolean retryChannel = false;

	private WifiP2pManager manager;
	private Channel channel;
	private WifiP2pInfo info;

	public static String getDeviceStatus(int deviceStatus) {
		Log.d(CameraActivity.TAG, "Peer status :" + deviceStatus);
		switch (deviceStatus) {
		case WifiP2pDevice.AVAILABLE:
			return "Available";
		case WifiP2pDevice.INVITED:
			return "Invited";
		case WifiP2pDevice.CONNECTED:
			return "Connected";
		case WifiP2pDevice.FAILED:
			return "Failed";
		case WifiP2pDevice.UNAVAILABLE:
			return "Unavailable";
		default:
			return "Unknown";
		}
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		this.setListAdapter(new WiFiPeerListAdapter(getActivity(), R.layout.row_devices, peers));
		if (((CameraActivity) getActivity()).getMode() == CameraActivity.CAMERA_MODE_ORIGINAL)
			getListView().setEnabled(false);
		((Button) getActivity().findViewById(R.id.wifi_turn_on_off_btn)).setOnClickListener(this);
		((Button) getActivity().findViewById(R.id.wifi_discover_btn)).setOnClickListener(this);
		((Button) mContentView.findViewById(R.id.client_connect_btn)).setOnClickListener(this);
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		mContentView = inflater.inflate(R.layout.device_list, null);
		return mContentView;
	}

	/**
	 * @return this device
	 */
	public WifiP2pDevice getDevice() {
		return serverDevice;
	}

	/**
	 * Initiate a connection with the peer.
	 */
	@Override
	public void onListItemClick(ListView l, View v, int position, long id) {
		WifiP2pDevice clientDevice = (WifiP2pDevice) getListAdapter().getItem(position);
		// debug
		showDetails(clientDevice);
		// connect to device
		WifiP2pConfig config = new WifiP2pConfig();
		config.deviceAddress = clientDevice.deviceAddress;
		config.groupOwnerIntent = 15;
		// config.wps.setup = WpsInfo.PBC;
		if (progressDialog != null && progressDialog.isShowing())
			progressDialog.dismiss();
		progressDialog = ProgressDialog.show(getActivity(), "Press back to cancel",
				"Connecting to :" + clientDevice.deviceAddress, true, true,
				new DialogInterface.OnCancelListener() {
					@Override
					public void onCancel(DialogInterface dialog) {
						cancelDisconnect();
					}
				});
		connect(config);
	}

	/**
	 * Update UI for this device.
	 * 
	 * @param device
	 *            WifiP2pDevice object
	 */
	public void updateThisDevice(WifiP2pDevice device) {
		this.serverDevice = device;
		TextView view = (TextView) mContentView.findViewById(R.id.my_name);
		view.setText(serverDevice.deviceName);
		view = (TextView) mContentView.findViewById(R.id.my_status);
		view.setText(getDeviceStatus(serverDevice.status));
	}

	@Override
	public void onPeersAvailable(WifiP2pDeviceList peerList) {
		if (progressDialog != null && progressDialog.isShowing())
			progressDialog.dismiss();
		peers.clear();
		peers.addAll(peerList.getDeviceList());
		((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
		if (peers.size() == 0) {
			Log.d(CameraActivity.TAG, "No devices found");
			return;
		}

	}

	public void clearPeers() {
		peers.clear();
		((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
	}

	/**
     * 
     */
	public void onInitiateDiscovery() {
		if (progressDialog != null && progressDialog.isShowing())
			progressDialog.dismiss();
		progressDialog = ProgressDialog.show(getActivity(), "Press back to cancel",
				"finding peers", true, true, new DialogInterface.OnCancelListener() {

					@Override
					public void onCancel(DialogInterface dialog) {

					}
				});
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		int id = v.getId();
		switch (id) {
		case R.id.wifi_discover_btn:
			if (!isWifiP2PEnabled) {
				Toast.makeText(getActivity(), "WiFiP2P is disabled", Toast.LENGTH_SHORT).show();
				return;
			}
			onInitiateDiscovery();
			discoverPeers();
			break;
		case R.id.wifi_turn_on_off_btn:
			// TODO Auto-generated method stub
			if (manager != null && channel != null) {
				// Since this is the system wireless settings activity, it's
				// not going to send us a result. We will be notified by
				// WiFiDeviceBroadcastReceiver instead.
				startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
			} else {
				Log.e(CameraActivity.TAG, "channel or manager is null");
			}
			break;
		case R.id.client_connect_btn:
			((CameraActivity) getActivity()).startClient(info.groupOwnerAddress.getHostAddress());
			((CameraActivity) getActivity()).setShowRemoteStateMessage();
			Log.d(CameraActivity.TAG, "DeviceListFragment:handleMessage:client_connect_btn");
			break;
		}
	}

	public void setWiFiP2PManager(WifiP2pManager manager) {
		this.manager = manager;
	}

	public void setChannel(Channel channel) {
		this.channel = channel;
	}

	@Override
	public void onChannelDisconnected() {
		// TODO Auto-generated method stub
		// we will try once more
		if (manager != null && !retryChannel) {
			Toast.makeText(getActivity(), "Channel lost. Trying again", Toast.LENGTH_LONG).show();
			clearPeers();
			retryChannel = true;
			manager.initialize(getActivity(), getActivity().getMainLooper(), this);
		} else {
			Toast.makeText(getActivity(),
					"Severe! Channel is probably lost premanently. Try Disable/Re-Enable P2P.",
					Toast.LENGTH_LONG).show();
		}
	}

	@Override
	public void onConnectionInfoAvailable(WifiP2pInfo info) {
		// TODO Auto-generated method stub
		// The owner IP is now known.
		// InetAddress from WifiP2pInfo struct.

		// After the group negotiation, we assign the group owner as the file
		// server. The file server is single threaded, single connection server
		// socket.
		if (info.groupFormed && info.isGroupOwner) {
			// start remote camera as a server
			((CameraActivity) getActivity()).startServer(info);
			// debug
			Toast.makeText(getActivity(), "Connection completely. I am a groupOwner!!",
					Toast.LENGTH_SHORT).show();
		} else if (info.groupFormed) {
			// The other device acts as the client.
			// In this case, we could enable connect button.
			((Button) mContentView.findViewById(R.id.client_connect_btn))
					.setVisibility(View.VISIBLE);
			this.info = info;
			// debug
			Toast.makeText(getActivity(), "Connection completely. I am a other device!!",
					Toast.LENGTH_SHORT).show();
		}
	}

	@Override
	public void showDetails(WifiP2pDevice device) {
		// TODO Auto-generated method stub
		// show device detail info
		// debug
		Toast.makeText(getActivity(), serverDevice.toString(), Toast.LENGTH_SHORT).show();
	}

	@Override
	public void cancelDisconnect() {
		// TODO Auto-generated method stub
		/*
		 * A cancel abort request by user. Disconnect i.e. removeGroup if
		 * already connected. Else, request WifiP2pManager to abort the ongoing
		 * request
		 */
		if (manager != null) {
			if (serverDevice == null || serverDevice.status == WifiP2pDevice.CONNECTED) {
				disconnect();
			} else if (serverDevice.status == WifiP2pDevice.AVAILABLE
					|| serverDevice.status == WifiP2pDevice.INVITED) {

				manager.cancelConnect(channel, new ActionListener() {

					@Override
					public void onSuccess() {
						Toast.makeText(getActivity(), "Aborting connection", Toast.LENGTH_SHORT)
								.show();
					}

					@Override
					public void onFailure(int reasonCode) {
						Toast.makeText(getActivity(),
								"Connect abort request failed. Reason Code: " + reasonCode,
								Toast.LENGTH_SHORT).show();
					}
				});
			}
		}
	}

	@Override
	public void connect(WifiP2pConfig config) {
		// TODO Auto-generated method stub
		manager.connect(channel, config, new ActionListener() {

			@Override
			public void onSuccess() {
				// WiFiDirectBroadcastReceiver will notify us. Ignore for now.
			}

			@Override
			public void onFailure(int reason) {
				Toast.makeText(getActivity(), "Connect failed. Retry.", Toast.LENGTH_SHORT).show();
			}
		});
	}

	@Override
	public void disconnect() {
		// TODO Auto-generated method stub
		manager.removeGroup(channel, new ActionListener() {

			@Override
			public void onFailure(int reasonCode) {
				Log.d(CameraActivity.TAG, "Disconnect failed. Reason :" + reasonCode);

			}

			@Override
			public void onSuccess() {
				Log.d(CameraActivity.TAG, "disconnect Success");
				// Toast.makeText(getActivity(), "disconnect Success",
				// Toast.LENGTH_SHORT).show();
			}

		});
	}

	@Override
	public void discoverPeers() {
		// TODO Auto-generated method stub
		manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {

			@Override
			public void onSuccess() {
				Toast.makeText(getActivity(), "Discovery Initiated", Toast.LENGTH_SHORT).show();
			}

			@Override
			public void onFailure(int reasonCode) {
				Toast.makeText(getActivity(), "Discovery Failed : " + reasonCode,
						Toast.LENGTH_SHORT).show();
			}
		});
	}

	@Override
	public void setWiFiTurnOnOff() {
		// TODO Auto-generated method stub
		if (manager != null && channel != null) {
			// Since this is the system wireless settings activity, it's
			// not going to send us a result. We will be notified by
			// WiFiDeviceBroadcastReceiver instead.
			startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
		} else {
			Log.e(CameraActivity.TAG, "channel or manager is null");
		}
	}

	public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled) {
		this.isWifiP2PEnabled = isWifiP2pEnabled;
	}

	public boolean isWifiP2PEnabled() {
		return isWifiP2PEnabled;
	}

	public void setVisibility(int visibility) {
		mContentView.setVisibility(visibility);
	}
}
/* end of file */
